#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/of_gpio.h>

struct virtual_spi_master{
	struct spi_bitbang bitbang;
	struct completion xfer_done;
};

static int spi_virtual_setup(struct spi_device *spi_dev)
{
	//若采用的传统GPIO模式还需要在驱动中将gpio设置为输出
	if (!gpio_is_valid(spi_dev->cs_gpio))
	{
		printk("%d is not a valid gpio\n", spi_dev->cs_gpio);
		return -EINVAL;
	}

	return gpio_direction_output(spi_dev->cs_gpio, !(spi_dev->mode & SPI_CS_HIGH));
}

static void	spi_virtual_chipselect(struct spi_device *spi, int is_on)
{
	int active = is_on != BITBANG_CS_INACTIVE;
	int dev_is_lowactive = !(spi->mode & SPI_CS_HIGH);

	if (spi->mode & SPI_NO_CS)
		return;

	if (!gpio_is_valid(spi->cs_gpio))
		return;

	gpio_set_value(spi->cs_gpio, dev_is_lowactive ^ active);
}

static int spi_virtual_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{
	return 0;
}

static int spi_virtual_transfer(struct spi_device *spi, struct spi_transfer *transfer)
{
	int timeout;
	struct virtual_spi_master *virtual_master = spi_master_get_devdata(spi->master);

	//重置complete
	reinit_completion(&virtual_master->xfer_done);

	//启动硬件传输
	printk("transfer one\n");

	//传输完成后调用，一般在中断中调用
	complete(&virtual_master->xfer_done);

	//等待传输完成
	timeout = wait_for_completion_timeout(&virtual_master->xfer_done, 100);
	if (!timeout) {
		printk("I/O Error in PIO\n");
		return -ETIMEDOUT;
	}

	return transfer->len;
}

static int spi_virtual_probe(struct platform_device *pdev)
{
	int result;
	int i, num_cs, cs_gpio;
	struct spi_master *master;
	struct virtual_spi_master *virtual_master;

	printk("%s\r\n", __FUNCTION__);
	//分配 spi_master 和 virtual_spi_master
	master = spi_alloc_master(&pdev->dev, sizeof(struct virtual_spi_master));
	if(!master)
	{
		printk("alloc spi_master fail\n");
		return -ENOMEM;
	}

	//获取分配的 virtual_spi_master
	virtual_master = spi_master_get_devdata(master);

	//初始化 virtual_spi_master
	init_completion(&virtual_master->xfer_done);

	//初始化 spi_bitbang
	virtual_master->bitbang.master = master;
	virtual_master->bitbang.chipselect = spi_virtual_chipselect;
	virtual_master->bitbang.setup_transfer = spi_virtual_setup_transfer;
	virtual_master->bitbang.txrx_bufs = spi_virtual_transfer;
	//初始化 spi_master
	virtual_master->bitbang.master->setup = spi_virtual_setup;
	virtual_master->bitbang.master->dev.of_node = pdev->dev.of_node;
	virtual_master->bitbang.master->bus_num = pdev->id;
	virtual_master->bitbang.master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_3WIRE;

	/* SPI驱动框架仅仅是从设备树中获取片选引脚并记录，未进行request引脚 */
	num_cs = of_gpio_named_count(pdev->dev.of_node, "cs-gpios");
	for (i = 0; i < num_cs; i++)
	{
		cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i);
		if (cs_gpio == -EPROBE_DEFER)
		{
			spi_master_put(virtual_master->bitbang.master);
			return -EPROBE_DEFER;
		}

		if(gpio_is_valid(cs_gpio))
		{
			result = devm_gpio_request(&pdev->dev, cs_gpio, "virtual_spi_cs");
			if(result < 0)
			{
				spi_master_put(virtual_master->bitbang.master);
				printk("can't get CS gpio %i\n", cs_gpio);
				return result;
			}
		}
	}

	//启动spi_bitbang
	result = spi_bitbang_start(&virtual_master->bitbang);
	if (result < 0) {
		printk("spi_bitbang_start fail\n");
		spi_master_put(virtual_master->bitbang.master);
		return result;
	}

	//设置平台设备的驱动私有数据
	pdev->dev.driver_data = (void*)virtual_master;

	return 0;
}

static int spi_virtual_remove(struct platform_device *pdev)
{
	struct virtual_spi_master *virtual_master;

	printk("%s\r\n", __FUNCTION__);
	//提取平台设备的驱动私有数据
	virtual_master = (struct virtual_spi_master*)pdev->dev.driver_data;
	//停止spi_bitbang
	spi_bitbang_stop(&virtual_master->bitbang);

	return 0;
}

static const struct of_device_id spi_virtual_of_match[] = {
	{.compatible = "atk,virtual_spi_master"},
	{ /* Sentinel */ }
};
static struct platform_driver spi_virtual_driver = {
	.probe = spi_virtual_probe,
	.remove = spi_virtual_remove,
	.driver = {
		.name = "virtual_spi",
		.of_match_table = spi_virtual_of_match,
	},
};

static int virtual_master_init(void)
{
	printk("%s\r\n", __FUNCTION__);
	return platform_driver_register(&spi_virtual_driver);
}

static void virtual_master_exit(void)
{
	printk("%s\r\n", __FUNCTION__);
	platform_driver_unregister(&spi_virtual_driver);
}

module_init(virtual_master_init);
module_exit(virtual_master_exit);

MODULE_DESCRIPTION("virtual SPI bus driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lf");